home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
gnu
/
nethack.lha
/
nethack-3.1
/
src
/
dog.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-25
|
13KB
|
501 lines
/* SCCS Id: @(#)dog.c 3.1 92/10/18 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
#include "edog.h"
#define domestic(mtmp) (mtmp->data->msound == MS_BARK || \
mtmp->data->msound == MS_MEW)
#ifdef OVLB
static int NDECL(pet_type);
void
initedog(mtmp)
register struct monst *mtmp;
{
mtmp->mtame = domestic(mtmp) ? 10 : 5;
mtmp->mpeaceful = 1;
set_malign(mtmp); /* recalc alignment now that it's tamed */
mtmp->mleashed = 0;
mtmp->meating = 0;
EDOG(mtmp)->droptime = 0;
EDOG(mtmp)->dropdist = 10000;
EDOG(mtmp)->apport = 10;
EDOG(mtmp)->whistletime = 0;
EDOG(mtmp)->hungrytime = 1000 + moves;
}
static int
pet_type()
{
register int pettype;
switch (pl_character[0]) {
/* some character classes have restricted ideas of pets */
case 'C':
case 'S':
pettype = PM_LITTLE_DOG;
break;
case 'W':
pettype = PM_KITTEN;
break;
/* otherwise, see if the player has a preference */
default:
if (preferred_pet == 'c')
pettype = PM_KITTEN;
else if (preferred_pet == 'd')
pettype = PM_LITTLE_DOG;
else pettype = rn2(2) ? PM_KITTEN : PM_LITTLE_DOG;
break;
}
return pettype;
}
void
make_familiar(otmp,x,y)
register struct obj *otmp;
xchar x, y;
{
register struct monst *mtmp;
register struct permonst *pm;
top:
if (otmp) pm = &mons[otmp->corpsenm]; /* Figurine; otherwise spell */
else if (rn2(3)) {
if (!(pm = rndmonst())) {
pline("There seems to be nothing available for a familiar.");
return;
}
}
else pm = &mons[pet_type()];
pm->pxlth += sizeof(struct edog);
mtmp = makemon(pm, x, y);
pm->pxlth -= sizeof(struct edog);
if (!mtmp) { /* monster was genocided */
if (otmp)
pline("The figurine writhes and then shatters into pieces!");
else goto top;
/* rndmonst() returns something not genocided always, so this
* means it was a cat or dog; loop back to try again until
* either rndmonst() is called, or if only one of cat/dog
* was genocided, they get the other.
*/
return;
}
initedog(mtmp);
mtmp->msleep = 0;
if (otmp && otmp->cursed) { /* cursed figurine */
You("get a bad feeling about this.");
mtmp->mtame = mtmp->mpeaceful = 0;
newsym(mtmp->mx, mtmp->my);
}
set_malign(mtmp); /* more alignment changes */
}
struct monst *
makedog()
{
register struct monst *mtmp;
char *petname;
int pettype;
static int petname_used = 0;
pettype = pet_type();
if (pettype == PM_LITTLE_DOG)
petname = dogname;
else
petname = catname;
mons[pettype].pxlth = sizeof(struct edog);
mtmp = makemon(&mons[pettype], u.ux, u.uy);
mons[pettype].pxlth = 0;
if(!mtmp) return((struct monst *) 0); /* pets were genocided */
if (!petname_used++ && *petname)
mtmp = christen_monst(mtmp, petname);
initedog(mtmp);
return(mtmp);
}
void
losedogs()
{
register struct monst *mtmp,*mtmp0,*mtmp2;
int num_segs;
while(mtmp = mydogs){
mydogs = mtmp->nmon;
mtmp->nmon = fmon;
fmon = mtmp;
if (mtmp->isshk)
set_residency(mtmp, FALSE);
num_segs = mtmp->wormno;
/* baby long worms have no tail so don't use is_longworm() */
if ( (mtmp->data == &mons[PM_LONG_WORM]) &&
(mtmp->wormno = get_wormno()) ) {
initworm(mtmp, num_segs);
/* tail segs are not yet initialized or displayed */
} else mtmp->wormno = 0;
mnexto(mtmp);
}
#if defined(LINT) || defined(GCC_WARN)
mtmp0 = (struct monst *)0;
#endif
for(mtmp = migrating_mons; mtmp; mtmp = mtmp2) {
mtmp2 = mtmp->nmon;
if(mtmp->mx == u.uz.dnum && mtmp->mux == u.uz.dlevel) {
mtmp->mx = 0; /* save xyloc in mtmp->my */
mtmp->mux = u.ux; mtmp->muy = u.uy; /* not really req'd */
if(mtmp == migrating_mons)
migrating_mons = mtmp->nmon;
else
mtmp0->nmon = mtmp->nmon;
mtmp->nmon = fmon;
fmon = mtmp;
num_segs = mtmp->wormno;
if ( (mtmp->data == &mons[PM_LONG_WORM]) &&
(mtmp->wormno = get_wormno()) ) {
initworm(mtmp, num_segs);
/* tail segs are not yet initialized or displayed */
} else mtmp->wormno = 0;
if(mtmp->mlstmv < monstermoves-1) {
/* heal monster for time spent in limbo */
long nmv = monstermoves - mtmp->mlstmv - 1;
/* might stop being afraid, blind or frozen */
/* set to 1 and allow final decrement in movemon() */
if(nmv >= (long)mtmp->mblinded) mtmp->mblinded = 1;
else mtmp->mblinded -= nmv;
if(nmv >= (long)mtmp->mfrozen) mtmp->mfrozen = 1;
else mtmp->mfrozen -= nmv;
if(nmv >= (long)mtmp->mfleetim) mtmp->mfleetim = 1;
else mtmp->mfleetim -= nmv;
/* might be able to use special ability again */
if(nmv > (long)mtmp->mspec_used) mtmp->mspec_used = 0;
else mtmp->mspec_used -= nmv;
if(!regenerates(mtmp->data)) nmv /= 20;
if((long)mtmp->mhp + nmv >= (long)mtmp->mhpmax)
mtmp->mhp = mtmp->mhpmax;
else mtmp->mhp += nmv;
mtmp->mlstmv = monstermoves-1;
}
if (mtmp->data->geno & G_GENOD) {
#ifdef KOPS
allow_kops = FALSE;
#endif
mondead(mtmp); /* must put in fmon list first */
#ifdef KOPS
allow_kops = TRUE;
#endif
} else if (mtmp->isshk && mtmp->mpeaceful)
home_shk(mtmp, TRUE);
else switch(mtmp->my) {
xchar *xlocale, *ylocale;
case 1: xlocale = &xupstair; ylocale = &yupstair;
goto common;
case 2: xlocale = &xdnstair; ylocale = &ydnstair;
goto common;
case 3: xlocale = &xupladder; ylocale = &yupladder;
goto common;
case 4: xlocale = &xdnladder; ylocale = &ydnladder;
goto common;
case 5: xlocale = &sstairs.sx; ylocale = &sstairs.sy;
goto common;
common:
if (*xlocale && *ylocale) {
(void) mnearto(mtmp, *xlocale, *ylocale, FALSE);
break;
} /* else fall through */
default:
rloc(mtmp);
break;
}
} else
mtmp0 = mtmp;
if (mtmp->isshk)
set_residency(mtmp, FALSE);
}
}
#endif /* OVLB */
#ifdef OVL2
void
keepdogs()
{
register struct monst *mtmp;
register struct obj *obj;
int num_segs = 0;
for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
if(((monnear(mtmp, u.ux, u.uy) && levl_follower(mtmp)) ||
/* the wiz will level t-port from anywhere to chase
the amulet; if you don't have it, will chase you
only if in range. -3. */
(u.uhave.amulet && mtmp->iswiz))
&& !mtmp->msleep && mtmp->mcanmove) {
/* long worms can now change levels! - Norm */
if (mtmp->mtame && mtmp->meating && canseemon(mtmp)) {
pline("%s is still eating.", Monnam(mtmp));
goto merge;
}
if (mon_has_amulet(mtmp)) {
pline("%s seems very disoriented for a moment.",
Monnam(mtmp));
merge:
#ifdef WALKIES
if (mtmp->mleashed) {
pline("%s leash suddenly comes loose.",
humanoid(mtmp->data)
? (mtmp->female ? "Her" : "His")
: "Its");
m_unleash(mtmp);
}
#endif
continue;
}
if (mtmp->isshk)
set_residency(mtmp, TRUE);
if (mtmp->wormno) {
/* NOTE: worm is truncated to # segs = max wormno size */
num_segs = min(count_wsegs(mtmp), MAX_NUM_WORMS - 1);
wormgone(mtmp);
}
/* set minvent's obj->no_charge to 0 */
for(obj = mtmp->minvent; obj; obj = obj->nobj) {
if(Is_container(obj))
picked_container(obj); /* does the right thing */
obj->no_charge = 0;
}
relmon(mtmp);
newsym(mtmp->mx,mtmp->my);
mtmp->mx = mtmp->my = 0; /* avoid mnexto()/MON_AT() problem */
mtmp->wormno = num_segs;
mtmp->nmon = mydogs;
mydogs = mtmp;
keepdogs(); /* we destroyed the link, so use recursion */
return; /* (admittedly somewhat primitive) */
}
}
#endif /* OVL2 */
#ifdef OVLB
void
migrate_to_level(mtmp, tolev, xyloc)
register struct monst *mtmp;
xchar tolev; /* destination level */
xchar xyloc; /* destination xy location: */
/* 0: rnd,
* 1: <,
* 2: >,
* 3: < ladder,
* 4: > ladder,
* 5: sstairs
*/
{
register struct obj *obj;
int num_segs = 0; /* count of worm segments */
if (mtmp->isshk)
set_residency(mtmp, TRUE);
if (mtmp->wormno) {
/* **** NOTE: worm is truncated to # segs = max wormno size **** */
num_segs = min(count_wsegs(mtmp), MAX_NUM_WORMS - 1);
wormgone(mtmp);
}
/* set minvent's obj->no_charge to 0 */
for(obj = mtmp->minvent; obj; obj = obj->nobj) {
if(Is_container(obj))
picked_container(obj); /* does the right thing */
obj->no_charge = 0;
}
relmon(mtmp);
mtmp->nmon = migrating_mons;
migrating_mons = mtmp;
#ifdef WALKIES
if (mtmp->mleashed) {
pline("The leash comes off!");
m_unleash(mtmp);
}
#endif
mtmp->mtame = 0;
newsym(mtmp->mx,mtmp->my);
/* make sure to reset mtmp->[mx,my] to 0 when releasing, */
/* so rloc() on next level doesn't affect MON_AT() state */
mtmp->mx = ledger_to_dnum((xchar)tolev);
mtmp->mux = ledger_to_dlev((xchar)tolev);
mtmp->my = xyloc;
mtmp->muy = 0;
mtmp->wormno = num_segs;
mtmp->mlstmv = monstermoves;
}
#endif /* OVLB */
#ifdef OVL1
/* return quality of food; the lower the better */
/* fungi will eat even tainted food */
int
dogfood(mon,obj)
struct monst *mon;
register struct obj *obj;
{
boolean carni = carnivorous(mon->data);
boolean herbi = herbivorous(mon->data);
struct permonst *fptr = &mons[obj->corpsenm];
switch(obj->oclass) {
case FOOD_CLASS:
if (obj->otyp == CORPSE &&
((obj->corpsenm == PM_COCKATRICE && !resists_ston(mon->data))
|| is_rider(fptr)))
return TABU;
if (!carni && !herbi)
return (obj->cursed ? UNDEF : APPORT);
switch (obj->otyp) {
case TRIPE_RATION:
return (carni ? DOGFOOD : MANFOOD);
case EGG:
if (obj->corpsenm == PM_COCKATRICE &&
!resists_ston(mon->data))
return POISON;
return (carni ? CADAVER : MANFOOD);
case CORPSE:
if ((obj->age+50 <= monstermoves
&& obj->corpsenm != PM_LIZARD
&& mon->data->mlet != S_FUNGUS) ||
(acidic(&mons[obj->corpsenm]) &&
!resists_acid(mon->data)) ||
(poisonous(&mons[obj->corpsenm]) &&
!resists_poison(mon->data)))
return POISON;
else if (fptr->mlet == S_FUNGUS)
return (herbi ? CADAVER : MANFOOD);
else if (is_meaty(fptr))
return (carni ? CADAVER : MANFOOD);
else return (carni ? ACCFOOD : MANFOOD);
case CLOVE_OF_GARLIC:
return (is_undead(mon->data) ? TABU :
(herbi ? ACCFOOD : MANFOOD));
case TIN:
return (metallivorous(mon->data) ? ACCFOOD : MANFOOD);
case APPLE:
case CARROT:
return (herbi ? DOGFOOD : MANFOOD);
case BANANA:
return ((mon->data->mlet == S_YETI) ? DOGFOOD :
(herbi ? ACCFOOD : MANFOOD));
default:
#ifdef TUTTI_FRUTTI
return (obj->otyp > SLIME_MOLD ?
#else
return (obj->otyp > CLOVE_OF_GARLIC ?
#endif
(carni ? ACCFOOD : MANFOOD) :
(herbi ? ACCFOOD : MANFOOD));
}
default:
if (hates_silver(mon->data) &&
objects[obj->otyp].oc_material == SILVER)
return(TABU);
if (mon->data == &mons[PM_GELATINOUS_CUBE] && is_organic(obj))
return(ACCFOOD);
if (metallivorous(mon->data) && is_metallic(obj))
/* Ferrous based metals are preferred. */
return(objects[obj->otyp].oc_material == IRON ? DOGFOOD :
ACCFOOD);
if(!obj->cursed && obj->oclass != BALL_CLASS &&
obj->oclass != CHAIN_CLASS)
return(APPORT);
/* fall into next case */
case ROCK_CLASS:
return(UNDEF);
}
}
#endif /* OVL1 */
#ifdef OVLB
struct monst *
tamedog(mtmp, obj)
register struct monst *mtmp;
register struct obj *obj;
{
register struct monst *mtmp2;
/* The Wiz, Medusa and the quest nemeses aren't even made peaceful. */
if (mtmp->iswiz || mtmp->data == &mons[PM_MEDUSA]
#ifdef MULDGN
|| (mtmp->data->mflags3 & M3_WANTSARTI)
#endif
)
return((struct monst *)0);
/* worst case, at least he'll be peaceful. */
mtmp->mpeaceful = 1;
set_malign(mtmp);
if(flags.moonphase == FULL_MOON && night() && rn2(6) && obj
&& mtmp->data->mlet == S_DOG)
return((struct monst *)0);
/* If we cannot tame him, at least he's no longer afraid. */
mtmp->mflee = 0;
mtmp->mfleetim = 0;
if(mtmp->mtame || !mtmp->mcanmove ||
/* monsters with conflicting structures cannot be tamed */
mtmp->isshk || mtmp->isgd || mtmp->ispriest || mtmp->isminion ||
#ifdef POLYSELF
is_human(mtmp->data) || (is_demon(mtmp->data) && !is_demon(uasmon))
#else
is_human(mtmp->data) || is_demon(mtmp->data)
#endif
|| (mtmp->data->mflags3 &
(M3_WANTSAMUL|M3_WANTSBELL|M3_WANTSBOOK|M3_WANTSCAND))
)
return((struct monst *)0);
if(obj) {
if(dogfood(mtmp, obj) >= MANFOOD) return((struct monst *)0);
if(cansee(mtmp->mx,mtmp->my))
pline("%s devours the %s.", Monnam(mtmp), xname(obj));
obfree(obj, (struct obj *)0);
}
if (u.uswallow && mtmp == u.ustuck)
expels(mtmp, mtmp->data, TRUE);
mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth);
*mtmp2 = *mtmp;
mtmp2->mxlth = sizeof(struct edog);
if(mtmp->mnamelth) Strcpy(NAME(mtmp2), NAME(mtmp));
initedog(mtmp2);
replmon(mtmp,mtmp2);
newsym(mtmp2->mx, mtmp2->my);
return(mtmp2);
}
#endif /* OVLB */
/*dog.c*/